/**
 * No Rights Reserved.
 * This program and the accompanying materials
 * are made available under the terms of the Public Domain.
 */
package logbook.server.proxy;

import java.awt.List;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.net.URLDecoder;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Scanner;

import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.HttpRequest;
import org.eclipse.jetty.client.api.ContentProvider;
import org.eclipse.jetty.client.api.ProxyConfiguration;
import org.eclipse.jetty.client.api.Request;
import org.eclipse.jetty.client.api.Response;
import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.proxy.ProxyServlet;

import com.charlygao.MainWindow;


public final class ReverseProxyServlet extends ProxyServlet {


    private static final Field QUERY_FIELD = getDeclaredField(HttpRequest.class, "query");


    @Override
    protected void customizeProxyRequest(Request proxyRequest, HttpServletRequest request) {
        proxyRequest.onRequestContent(new RequestContentListener(request));
        proxyRequest.header(HttpHeader.VIA, null);
        proxyRequest.header(HttpHeader.X_FORWARDED_FOR, null);
        proxyRequest.header(HttpHeader.X_FORWARDED_PROTO, null);
        proxyRequest.header(HttpHeader.X_FORWARDED_HOST, null);
        proxyRequest.header(HttpHeader.X_FORWARDED_SERVER, null);
        proxyRequest.header("Origin", null);
        

        String queryString = ((org.eclipse.jetty.server.Request) request).getQueryString();
        fixQueryString(proxyRequest, queryString);
        
        
        if (request.getRequestURI().equals("/kcsapi/api_port/port"))
        {
        	try {
				request.setCharacterEncoding("UTF-8");
				byte[] b = new byte[1024];
				InputStream is = request.getInputStream();
				Scanner s = new java.util.Scanner(is);
				String paramsString = s.nextLine();
				String apiPort = getQueryMap(paramsString).get("api%5Fport");
				MainWindow.kcs.referer = request.getHeader("Referer");
				MainWindow.kcs.flashVersion = request.getHeader("x-flash-version");
				
				String apiToken = getQueryMap(paramsString).get("api%5Ftoken");
				//System.out.println(apiToken);
				MainWindow.kcs.token = apiToken;
        		//System.out.println("S: " + apiPort);
        		//System.out.println("L: " + MainWindow.ls.getPortTime());
        		//final String newParamsString = paramsString.replaceAll(apiPort, MainWindow.ls.getPortTime());
        		final String newParamsString = paramsString;
        		ContentProvider cp = new ContentProvider() {
					
					@Override
					public Iterator<ByteBuffer> iterator() {
						ByteBuffer buffer = ByteBuffer.wrap(newParamsString.getBytes());
						ArrayList<ByteBuffer> list = new ArrayList<ByteBuffer>();
						list.add(buffer);
						return list.iterator();
					}
					
					@Override
					public long getLength() {
						return newParamsString.length();
					}
				};
				proxyRequest.content(cp);
				
			} catch (UnsupportedEncodingException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
        }
		
        super.customizeProxyRequest(proxyRequest, request);
    }

    @Override
    protected void onResponseContent(HttpServletRequest request, HttpServletResponse response,
            Response proxyResponse,
            byte[] buffer, int offset, int length) throws IOException {

        if (Filter.isNeed(request.getServerName(), response.getContentType())) {
            ByteArrayOutputStream stream = (ByteArrayOutputStream) request.getAttribute(Filter.RESPONSE_BODY);
            if (stream == null) {
                stream = new ByteArrayOutputStream();
                request.setAttribute(Filter.RESPONSE_BODY, stream);
            }
            stream.write(buffer, offset, length);
        }

        super.onResponseContent(request, response, proxyResponse, buffer, offset, length);
    }


    @Override
    protected void onResponseSuccess(HttpServletRequest request, HttpServletResponse response,
            Response proxyResponse) {

        if (Filter.isNeed(request.getServerName(), response.getContentType())) {
            byte[] postField = (byte[]) request.getAttribute(Filter.REQUEST_BODY);
            ByteArrayOutputStream stream = (ByteArrayOutputStream) request.getAttribute(Filter.RESPONSE_BODY);
            if (stream != null) {
                
            	//System.out.println(request.getRequestURI());
            	if (request.getRequestURI().equals("/kcsapi/api_port/port"))
            	{
            		String poststr = "";
            		try {
						poststr = URLDecoder.decode(new String(postField).trim(), "UTF-8");
					} catch (UnsupportedEncodingException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
            		//String apiPort = getQueryMap(poststr).get("api_port");
            		//System.out.println("S: " + apiPort);
            		//System.out.println("L: " + MainWindow.ls.getPortTime());
            		MainWindow.kcs.api_port_port(new String(stream.toByteArray()));
            	}
            	/*

                Data data = new UndefinedData(request.getRequestURI(), postField, stream.toByteArray()).toDefinedData();
                if (data.getDataType() != DataType.UNDEFINED) {
                    DataQueue.add(data);
                    if (!Filter.isServerDetected()) {
                        Filter.setServerName(request.getServerName());
                    }
                }*/
            }
        }
        super.onResponseSuccess(request, response, proxyResponse);
    }

    /*
     * HttpClient
     */
    @Override
    protected HttpClient newHttpClient() {
        HttpClient client = super.newHttpClient();

        
            int port = 8099;
            String host = "127.0.0.1";
            client.setProxyConfiguration(new ProxyConfiguration(host, port));
      
        return client;
    }


    private static <T> Field getDeclaredField(Class<T> clazz, String string) {
        try {
            Field field = clazz.getDeclaredField(string);
            field.setAccessible(true);
            return field;
        } catch (ReflectiveOperationException e) {
            throw new RuntimeException(e);
        }
    }

    private static void fixQueryString(Request proxyRequest, String queryString) {
        if (!StringUtils.isEmpty(queryString)) {
            if (proxyRequest instanceof HttpRequest) {
                try {
                    QUERY_FIELD.set(proxyRequest, queryString);
                } catch (IllegalArgumentException | IllegalAccessException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }
    
    private static Map<String, String> getQueryMap(String query) {
        String[] params = query.split("&");
        Map<String, String> map = new HashMap<String, String>();
        for (String param : params) {
            String[] splited = param.split("=");
            String name = splited[0];
            String value = null;
            if (splited.length == 2) {
                value = splited[1];
            }
            map.put(name, value);
        }
        return map;
    }
}
